package com.hhc.interview;

import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.*;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.*;
import org.apache.lucene.store.RAMDirectory;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

public class T {
    private RAMDirectory mmapDirectory;
    private IndexWriter indexWriter;
    private IndexSearcher indexSearcher;

    public T() throws IOException {
        mmapDirectory = new RAMDirectory();
        IndexWriterConfig config = new IndexWriterConfig(new StandardAnalyzer());
        indexWriter = new IndexWriter(mmapDirectory, config);
    }

    public void loadDocs(List<Document> docs) throws IOException {
        for (Document doc : docs) {
            indexWriter.addDocument(doc);
        }
        indexWriter.commit();
        restartIndexSearcher();
    }

    public void updateDocs(List<Document> docs) throws IOException {
        for (Document doc : docs) {
            indexWriter.updateDocument(new Term("id", doc.get("id").toString()), doc);
        }
        indexWriter.commit();
        restartIndexSearcher();
    }

    public List<Document> searchDocs(int page, int pageSize, String query, List<String> statusList, long startTime, long endTime) throws IOException {
        BooleanQuery.Builder bq = new BooleanQuery.Builder();
        if (query != null && !query.isEmpty()) {
            bq.add(new TermQuery(new Term("title", query)), BooleanClause.Occur.SHOULD);
        }
        if (statusList != null && !statusList.isEmpty()) {
            for (String status : statusList) {
                bq.add(new TermQuery(new Term("status", status)), BooleanClause.Occur.SHOULD);
            }
        }
        if (startTime > 0 && endTime > 0) {
            bq.add(LongPoint.newRangeQuery("time", startTime, endTime), BooleanClause.Occur.SHOULD);
        }
        Query luceneQuery = bq.build();

        Sort sort = new Sort(new SortField("id", SortField.Type.LONG, true));

        indexSearcher = new IndexSearcher(DirectoryReader.open(mmapDirectory));
        int fromIndex = (page - 1) * pageSize;
        int toIndex = Math.min(fromIndex + pageSize, indexSearcher.getIndexReader().maxDoc());
        TopDocs topDocs = indexSearcher.search(luceneQuery, toIndex, sort);

        List<Document> docsList = new ArrayList<>();
        for (ScoreDoc scoreDoc : topDocs.scoreDocs) {
            docsList.add(indexSearcher.doc(scoreDoc.doc));
        }

        return docsList;
    }

    public long countDocs(String query, List<String> statusList, long startTime, long endTime) throws IOException {
        BooleanQuery.Builder bq = new BooleanQuery.Builder();
        if (query != null && !query.isEmpty()) {
            bq.add(new TermQuery(new Term("title", query)), BooleanClause.Occur.SHOULD);
        }
        if (statusList != null && !statusList.isEmpty()) {
            for (String status : statusList) {
                bq.add(new TermQuery(new Term("status", status)), BooleanClause.Occur.SHOULD);
            }
        }
        if (startTime > 0 && endTime > 0) {
            bq.add(LongPoint.newRangeQuery("time", startTime, endTime), BooleanClause.Occur.SHOULD);
        }
        Query luceneQuery = bq.build();

        return indexSearcher.count(luceneQuery);
    }

    private void restartIndexSearcher() throws IOException {
        indexSearcher = new IndexSearcher(DirectoryReader.open(mmapDirectory));
    }
}